namespace tb
{

	TB_INLINE Vec4::Vec4() 
	{

	}
	TB_INLINE Vec4::Vec4(const Vec3& a_Vector, float a_W /*= 1.f*/)
	{
		x = a_Vector.x;
		y = a_Vector.y;
		z = a_Vector.z;
		w = a_W;
	}
	TB_INLINE Vec4::Vec4(float a_X, float a_Y, float a_Z, float a_W)
	{
		x = a_X;
		y = a_Y;
		z = a_Z;
		w = a_W;
	}
	TB_INLINE Vec4::Vec4(const Vec4& a_Copy)
	{
		x = a_Copy.x;
		y = a_Copy.y;
		z = a_Copy.z;
		w = a_Copy.w;
	}
	TB_INLINE Vec4::~Vec4()
	{

	}

	// ================================
	// Assignment & Access
	// ================================

	TB_INLINE Vec4& Vec4::operator = (const Vec4& a_Point)
	{
		x = a_Point.x;
		y = a_Point.y;
		z = a_Point.z;
		w = a_Point.w;

		return *this;
	}
	TB_INLINE Vec4& Vec4::operator = (const Vec3& a_Point)
	{
		x = a_Point.x;
		y = a_Point.y;
		z = a_Point.z;
		w = 1.f;

		return *this;
	}
	TB_INLINE Vec4& Vec4::operator = (float a_Value)
	{
		x = y = z = w = a_Value;
		return *this;
	}

	TB_INLINE float& Vec4::operator [] (int a_Member)
	{
		return (&x)[a_Member];
	}

	TB_INLINE float Vec4::operator [] (int a_Member) const
	{
		return (&x)[a_Member];
	}

	TB_INLINE Vec4& Vec4::operator += (const Vec4& a_Other)
	{
		x += a_Other.x;
		y += a_Other.y;
		z += a_Other.z;
		w += a_Other.w;

		return *this;
	}

	TB_INLINE Vec4 Vec4::operator * (float a_Scalar) const
	{
		return Vec4(
			x * a_Scalar, 
			y * a_Scalar, 
			z * a_Scalar, 
			w * a_Scalar
		);
	}

	// ================================
	// Functions
	// ================================

	TB_INLINE Vec3 Vec4::Project() const
	{
		float rcp_w = 1.f / w;
		return Vec3(x * rcp_w, y * rcp_w, z * rcp_w);
	}

	TB_INLINE Vec4& Vec4::GetProjected(Vec3& a_Target)
	{
		float rcp_w = 1.f / w;
		a_Target.x = x * rcp_w;
		a_Target.y = y * rcp_w;
		a_Target.z = z * rcp_w;

		return *this;
	}

}